package com.norma.netty.study.netty.ws;

import cn.hutool.core.util.ZipUtil;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.HttpClientCodec;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.websocketx.*;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import io.netty.handler.stream.ChunkedWriteHandler;
import lombok.extern.slf4j.Slf4j;

import java.net.URI;
import java.nio.charset.StandardCharsets;

/**
 * @author zhangchaofeng
 * @date 2021/5/18
 * @description
 */
@Slf4j
public class WebSocketClient {

    private static final String WS_URL = "ws://192.168.110.199:12500/ws";


    public static void main(String[] args) {
        for (int i = 0; i < 20; i++) {
            new Thread(() -> {
                final Channel channel;
                NioEventLoopGroup group = new NioEventLoopGroup();
                try {
                    URI uri = new URI(WS_URL);
                    String scheme = uri.getScheme() == null ? "ws" : uri.getScheme();
                    String host = uri.getHost() == null ? "127.0.0.1" : uri.getHost();
                    int port = uri.getPort();
                    if (!"ws".equalsIgnoreCase(scheme) && !"wss".equalsIgnoreCase(scheme)) {
                        log.error("Only WS(S) is supported.");
                        return;
                    }

                    //ssl
                    final boolean ssl = "wss".equalsIgnoreCase(scheme);
                    final SslContext sslCtx;
                    if (ssl) {
                        sslCtx = SslContextBuilder.forClient()
                                .trustManager(InsecureTrustManagerFactory.INSTANCE).build();
                    } else {
                        sslCtx = null;
                    }
                    Bootstrap b = new Bootstrap()
                            .option(ChannelOption.SO_KEEPALIVE, true)
                            .option(ChannelOption.TCP_NODELAY, true)
                            .channel(NioSocketChannel.class)
                            .group(group)
                            .handler(new ChannelInitializer<SocketChannel>() {
                                @Override
                                protected void initChannel(SocketChannel ch) throws Exception {
                                    ChannelPipeline pipeline = ch.pipeline();
                                    if (sslCtx != null) {
//                                pipeline.addLast()
                                    }

                                    //http codec
                                    pipeline.addLast(new HttpClientCodec());
                                    //http数据传输时是分段的，需要聚合
                                    pipeline.addLast(new HttpObjectAggregator(8192));
                                    //分块
                                    pipeline.addLast(new ChunkedWriteHandler());
                                    /**数据压缩pipeline.addLast(WebSocketClientCompressionHandler.INSTANCE);*/
                                    pipeline.addLast("hookedHandler", new HandShakeHandler());
                                    pipeline.addLast(new WebSocketHandler());
                                }
                            });
                    channel = b.connect(uri.getHost(), uri.getPort()).sync().channel();
                    WebSocketClientHandshaker shaker = WebSocketClientHandshakerFactory
                            .newHandshaker(uri, WebSocketVersion.V13, null, true, new DefaultHttpHeaders());
                    HandShakeHandler hookedHandler = (HandShakeHandler) channel.pipeline().get("hookedHandler");
                    hookedHandler.setHandShaker(shaker);
                    //handShake
                    shaker.handshake(channel);
                    hookedHandler.getHandshakeFuture().sync();

                    sendMessage(channel);

                    channel.closeFuture().sync();

                } catch (Exception e) {
                    log.error("{}", e);

                } finally {
                    group.shutdownGracefully();
                }
            }).start();
        }

        System.out.println("-");
    }

    public static void sendMessage(Channel channel) {
        //发送的内容，是一个文本格式的内容
        String putMessage = "你好，我是客户端";
//        TextWebSocketFrame frame = new TextWebSocketFrame(putMessage);
        BinaryWebSocketFrame binaryWebSocketFrame = new BinaryWebSocketFrame(encode(putMessage));
        channel.writeAndFlush(binaryWebSocketFrame).addListener((ChannelFutureListener) channelFuture -> {
            if (channelFuture.isSuccess()) {
                log.info("消息发送成功，发送的消息是：{}", putMessage);
            } else {
                log.info("消息发送失败 {}", channelFuture.cause().getMessage());
            }
        });
    }

    public static ByteBuf encode(String msg) {
        byte[] bytes = msg.getBytes(StandardCharsets.UTF_8);
        byte[] gzip = ZipUtil.gzip(bytes);
        return Unpooled.wrappedBuffer(gzip);
    }


}
